package account

import (
	"fmt"
	"gitee.com/Hu-Lyndon/distill-resk/infra/validator"
	"gitee.com/Hu-Lyndon/distill-resk/services"
	"github.com/kataras/iris/core/errors"
	"github.com/shopspring/decimal"
	"sync"
)

//var _ services.AccountService = new(accountService)
var once sync.Once

// 通过init函数内调用sync.Once，实例化服务
func init() {
	once.Do(func() {
		services.IAccountService = new(accountService)
	})
}

type accountService struct {
}

func (a *accountService) CreateAccount(aDto services.AccountCreatedDTO) (*services.AccountDTO, error) {
	domain := accountDomain{}
	//验证输入参数
	if err := validator.ValidateStruct(&aDto); err != nil {
		return nil, err
	}
	//验证账户是否存在和幂等性
	acc := domain.GetAccountByUserIdAndType(aDto.UserId, services.AccountType(aDto.AccountType))
	if acc != nil {
		return acc, errors.New(
			fmt.Sprintf("用户的该类型账户已经存在：username=%s[%s],账户类型=%d",
				aDto.Username, aDto.UserId, aDto.AccountType))

	}
	//执行账户创建的业务逻辑
	amount, err := decimal.NewFromString(aDto.Amount)
	if err != nil {
		return nil, err
	}
	account := services.AccountDTO{
		UserId:       aDto.UserId,
		Username:     aDto.Username,
		AccountType:  aDto.AccountType,
		AccountName:  aDto.AccountName,
		CurrencyCode: aDto.CurrencyCode,
		Status:       1,
		Balance:      amount,
	}
	rdto, err := domain.Create(account)
	return rdto, err
}

func (a *accountService) Transfer(aDto services.AccountTransferDTO) (services.TransferedStatus, error) {
	//验证参数
	domain := accountDomain{}
	//验证输入参数
	if err := validator.ValidateStruct(&aDto); err != nil {
		return services.TransferedStatusFailure, err
	}
	//执行转账逻辑
	amount, err := decimal.NewFromString(aDto.AmountStr)
	if err != nil {
		return services.TransferedStatusFailure, err
	}
	aDto.Amount = amount
	if aDto.ChangeFlag == services.FlagTransferOut {
		if aDto.ChangeType > 0 {
			return services.TransferedStatusFailure,
				errors.New("如果changeFlag为支出，那么changeType必须小于0")
		}
	} else {
		if aDto.ChangeType < 0 {
			return services.TransferedStatusFailure,
				errors.New("如果changeFlag为收入,那么changeType必须大于0")
		}
	}

	status, err := domain.Transfer(aDto)
	//转账成功，并且交易主体和交易目标不是同一个人，而且交易类型不是储值，则进行反向操作
	if status == services.TransferedStatusSuccess && aDto.TradeBody.AccountNo != aDto.TradeTarget.AccountNo && aDto.ChangeType != services.AccountStoreValue {
		backwardDto := aDto
		backwardDto.TradeBody = aDto.TradeTarget
		backwardDto.TradeTarget = aDto.TradeBody
		backwardDto.ChangeType = -aDto.ChangeType
		backwardDto.ChangeFlag = -aDto.ChangeFlag
		status, err := domain.Transfer(backwardDto)
		return status, err
	}
	return status, err
}

func (a *accountService) StoreValue(aDto services.AccountTransferDTO) (services.TransferedStatus, error) {
	aDto.TradeTarget = aDto.TradeBody
	aDto.ChangeFlag = services.FlagTransferIn
	aDto.ChangeType = services.AccountStoreValue
	return a.Transfer(aDto)
}

func (a *accountService) GetEnvelopeAccountByUserId(userId string) *services.AccountDTO {
	domain := accountDomain{}
	account := domain.GetEnvelopeAccountByUserId(userId)
	return account
}

func (a *accountService) GetAccount(accountNo string) *services.AccountDTO {
	domain := accountDomain{}
	return domain.GetAccount(accountNo)
}
